﻿namespace Brjnk.Common
{
    using System;
    using System.ComponentModel;
    using Brjnk.Common.Extensions;
    using Brjnk.Common.ValueTypes;

    /// <summary>
    /// Vyjadřuje míru stoupání nebo klesání
    /// </summary>
    [TypeConverter(typeof(StringValueConverter<Slope>))]
    public struct Slope : IPhysicalQuantity
    {
        private double value; // tangens úhlu

        public Slope(double value)
        {
            this.value = value;
        }

        public double Degrees { get { return MathEx.ToDegrees(Math.Atan(value)); } }

        /// <summary>
        /// Tangenta úhlu
        /// </summary>
        public double Tangens { get { return value; } }

        /// <summary>
        /// Implicitní konverze vrací stoupání ve stupních
        /// </summary>
        public static implicit operator double(Slope s)
        {
            return s.Tangens;
        }

        public static implicit operator Slope(double a)
        {
            return new Slope(a);
        }

        public override string ToString()
        {
            switch (UnitsSettings.Instance.Slope)
            {
                case SlopeUnit.Degree:
                    return string.Format("{0:f02} {1}", Degrees, GetUnitName(SlopeUnit.Degree));
                case SlopeUnit.Percentage:
                    return string.Format("{0:p02}", Tangens);
                case SlopeUnit.PerMille:
                    return string.Format("{0:f02} " + StringExtension.PerMille, Tangens * 1000);
                default:
                    throw new ArgumentException("Nepodporovaná jednotka rychlosti.");
            }
        }

        static Slope()
        {
            Parser = new ValueParser();
            Parser.AddUnit("°", d => System.Math.Tan(MathEx.ToRadians(d)));
            Parser.AddUnit("%", 0.01);
            Parser.AddUnit(StringExtension.PerMille, 0.001);
        }

        public static readonly ValueParser Parser;

        public double GetValue()
        {
            return value;
        }

        public double GetCustomUnitValue()
        {
            return ToUnit(UnitsSettings.Instance.Slope);
        }

        public string GetCustomUnitName()
        {
            return GetUnitName(UnitsSettings.Instance.Slope);
        }

        public double ToUnit(SlopeUnit unit)
        {
            switch (unit)
            {
                case SlopeUnit.Degree:
                    return Degrees;
                case SlopeUnit.Percentage:
                    return Tangens;
                case SlopeUnit.PerMille:
                    return Tangens * 1000;
                default:
                    throw new Exception("Unknown unit");
            }
        }

        public static string GetUnitName(SlopeUnit unit)
        {
            switch (unit)
            {
                case SlopeUnit.Degree:
                    return "°";
                case SlopeUnit.Percentage:
                    return "%";
                case SlopeUnit.PerMille:
                    return StringExtension.PerMille;
                default:
                    throw new Exception("Unknown unit");
            }
        }

        public static string GetUnitName()
        {
            return GetUnitName(UnitsSettings.Instance.Slope);
        }
    }

    public enum SlopeUnit
    {
        Degree,
        Percentage,
        PerMille
    }
}